/**
 * @file   ModSync.java
 * @author Enrique Madrid <e.madrid@lpcsite.com>, Omar Quitana <o.quintana@lpcsite.com>
 * @date   Wed Aug 29 17:40:49 2007
 * 
 * @brief  Implementa el mecanismo de sincronización.
 * 
 * Esta paquete implementa el mecanismo de sincronización entre el aplicativo cliente
 * y el servidor.
 */

package sim.sync;

import sim.framework.*;
import sim.framework.io.*;
import sim.utils.*;
import sim.auth.*;

public final class ModSync extends Module {

    private static final int STAGE_COMMIT = 1;
    private static final int STAGE_UPDATE = 2;

    private DocSync m_DocSync = null;
    private DocAuth m_DocAuth = null;
    private int m_Stage;
    
    public ModSync(int id, Simlet s) {
        super(id, s);
    }
    
    public void work(final Msg msg) {
        switch(msg.getWParam()) {
	case Executable.STATE_INIT:
	    workInit(msg);
	    break;
	case Executable.STATE_NEXT:
	    workNext(msg);
	    break;
	case Executable.STATE_BACK:
	    workBack(msg);
	    break;
        }
    }

    private void workInit(final Msg msg) {
	//#ifdef DEBUG_MODSYNC
	//# System.out.println("ModSync::workInit() ENTERED");
	//#endif
	m_DocAuth = (DocAuth)getDocument(Simlet.MOD_AUTH);
	if (m_DocAuth != null) {
	    // Si no se ha creado un focumento de sincronización ...
	    m_DocSync = (DocSync)getDocument(Simlet.MOD_SYNC);
	    if (m_DocSync == null) {
		// Crear un nuevo documento de sincronización.
		m_DocSync = new DocSync(m_Simlet);
		// Asociar el documento de syncronizacion al framework
		setDocument(Simlet.MOD_SYNC, m_DocSync);
	    }
	    // Cargar la información de sincronización.
	    m_DocSync.load();
	    if (isTimeToUpdate(m_Simlet.currentTimeSeconds())) {
		//#ifdef DEBUG_MODSYNC
		//# System.out.println("\tEs hora de sincronizar!!!");
		//#endif
		execQueue(this, this);
		if (getAppCfgCommit()) {
		    //#ifdef DEBUG_MODSYNC
		    //# System.out.println("\tCarga de operaciones ...");
		    //#endif
		    m_Stage = STAGE_COMMIT;
		    exec(createModule(Simlet.MOD_SYCO));
		}
		else {
		    //#ifdef DEBUG_MODSYNC
		    //# System.out.println("\tDescarga de actualizaciones ...");
		    //#endif
		    m_Stage = ModSync.STAGE_UPDATE;
		    exec(createModule(Simlet.MOD_SYUP));
		}
	    }
	    else {
		//#ifdef DEBUG_MODSYNC
		//# System.out.println("\tNo es momento de sincronizar");
		//#endif
		execNext();
	    }
	}
	else {
	    //#ifdef DEBUG_MODSYNC
	    //# System.out.println("\tNo hay documento de autenticación!!!");
	    //#endif
	    execBack();
	}
	//#ifdef DEBUG_MODSYNC
	//# System.out.println("ModSync::workInit() EXITING");
	//#endif
    }

    private void workNext(final Msg msg) {
	//#ifdef DEBUG_MODSYNC
	//# System.out.println("ModSync::workNext() ENTERED");
	//#endif
	switch (m_Stage) {
	case ModSync.STAGE_COMMIT:
	    //#ifdef DEBUG_MODSYNC
	    //# System.out.println("\ttermino etapa STAGE_COMMIT, hora de la etapa STAGE_UPDATE");
	    //#endif
	    m_Stage = ModSync.STAGE_UPDATE;
	    execQueue(this, this);
	    exec(createModule(Simlet.MOD_SYUP));
	    break;
	case ModSync.STAGE_UPDATE:
	    //#ifdef DEBUG_MODSYNC
	    //# System.out.println("\ttodo termino, se actulizará marca de tiempo!!!");
	    //#endif
	    // Establecer el nuevo criterio de sincronización
	    m_DocSync.setTimeValue(m_Simlet.currentTimeSeconds());
	    // Guardar la referencia de sincronización
	    m_DocSync.save();
	    // Salimos del módulo Sync con éxito.
	    if (m_DocSync.restart()) {
		//#ifdef DEBUG_MODSYNC
		//# System.out.println("\tserá necesario reiniciar!!!");
		//#endif
		// Debe ingresar el password nuevamente.
		m_DocAuth.setPassword(null);
		// Reiniciar el applet ...
		exec(createModule(Simlet.MOD_INIT));
	    }
	    else {
		// Continuar ... 
		execNext();
	    }
	    break;
	}
	//#ifdef DEBUG_MODSYNC
	//# System.out.println("ModSync::workNext() EXITING");
	//#endif
    }

    private void workBack(final Msg msg) {

	//#ifdef DEBUG_MODSYNC
	//# System.out.println("ModSync::workBack() ENTERED");
	//#endif

	switch (m_Stage) {
	case ModSync.STAGE_COMMIT:
	    //#ifdef DEBUG_MODSYNC
	    //# System.out.println("\ttermino etapa STAGE_COMMIT, hora de la etapa STAGE_UPDATE");
	    //#endif
	    m_Stage = ModSync.STAGE_UPDATE;
	    execQueue(this, this);
	    exec(createModule(Simlet.MOD_SYUP));
	    break;
	case ModSync.STAGE_UPDATE:
	    //#ifdef DEBUG_MODSYNC
	    //# System.out.println("\ttodo termino, no se actuliza marca de tiempo!!!");
	    //#endif
	    execNext();
	    break;
	}

	//#ifdef DEBUG_MODSYNC
	//# System.out.println("ModSync::workBack() EXITING");
	//#endif

    }
        
    private boolean isTimeToUpdate(int currTime) {
	// Si el valor de configuración es cero ...
	if (getAppCfgSyncPer() == 0) {
	    // ... sincronizar siempre,
	    return true;
	    // si es mayor que cero ...
	}
        else if (getAppCfgSyncPer() > 0) {
	    // sincronizar si plazo de una nueva sincronización se ha cumplido
            return (currTime - m_DocSync.getTimeValue() >= getAppCfgSyncPer());
        }
	// No requiere sincronización.
        return false;
    }
}
